import 'dart:async';
import 'dart:convert';

import 'package:chatgreat/bloc/account_bloc.dart';
import 'package:chatgreat/bloc/chat_message_bloc.dart';
import 'package:chatgreat/bloc/room_bloc.dart';
import 'package:chatgreat/helper/ability.dart';
import 'package:chatgreat/helper/haptic_feedback.dart';
import 'package:chatgreat/helper/helper.dart';
import 'package:chatgreat/helper/my_widget.dart';
import 'package:chatgreat/lang/lang.dart';
import 'package:chatgreat/page/component/attached_button_panel.dart';
import 'package:chatgreat/page/component/chat/chat_share.dart';
import 'package:chatgreat/page/component/chat/enhanced_selectable_text.dart';
import 'package:chatgreat/page/component/chat/file_upload.dart';
import 'package:chatgreat/page/component/chat/message_state_manager.dart';
import 'package:chatgreat/page/component/dialog.dart';
import 'package:chatgreat/page/component/loading.dart';
import 'package:chatgreat/page/component/random_avatar.dart';
import 'package:chatgreat/page/component/theme/custom_size.dart';
import 'package:chatgreat/repo/api_server.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:chatgreat/page/component/theme/custom_theme.dart';
import 'package:chatgreat/page/component/chat/markdown.dart';
import 'package:chatgreat/repo/model/message.dart';
import 'package:clipboard/clipboard.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_localization/flutter_localization.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:go_router/go_router.dart';
import 'package:in_app_review/in_app_review.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:media_kit/ffi/ffi.dart';
import 'package:media_kit_video/media_kit_video_controls/src/controls/methods/video_state.dart';
import 'package:notification_center/notification_center.dart';
import 'package:quickalert/models/quickalert_type.dart';
import 'package:url_launcher/url_launcher_string.dart';

import '../../../helper/AppUtil.dart';
import '../../../helper/constant.dart';
import '../audio_player.dart';

class ChatPreview extends StatefulWidget {
  final int keyIndex;
  final List<MessageWithState> messages;
  final ScrollController? scrollController;
  final void Function(int id)? onDeleteMessage;
  final void Function()? onResetContext;
  final ChatPreviewController controller;
  final AudioPlayerController? audioPlayerController;
  final MessageStateManager? stateManager;
  final List<Widget>? helpWidgets;
  final Widget? questionWidget;
  final Widget? robotAvatar;
  final Widget? Function(Message message)? avatarBuilder;
  final Widget? Function(Message message)? senderNameBuilder;
  final bool supportBloc;
  final void Function(Message message)? onSpeakEvent;
  final void Function(Message message, int index)? onResentEvent;
  final void Function(Message message, int index)? onLikeEvent;
  final void Function(Message message, int index)? onCollectionEvent;
  final void Function()? onReadyAnimedEvent;
  final EdgeInsetsGeometry? padding;
  final Widget Function(Message message)? messageFooterBuilder;

  const ChatPreview({
    super.key,
    required this.keyIndex,
    required this.messages,
    this.scrollController,
    this.onDeleteMessage,
    this.onResetContext,
    required this.controller,
    this.audioPlayerController,
    this.stateManager,
    this.robotAvatar,
    this.avatarBuilder,
    this.senderNameBuilder,
    this.helpWidgets,
    this.questionWidget,
    this.onSpeakEvent,
    this.onResentEvent,
    this.onLikeEvent,
    this.onCollectionEvent,
    this.onReadyAnimedEvent,
    this.supportBloc = true,
    this.padding,
    this.messageFooterBuilder,
  });

  @override
  ChatPreviewState createState() => ChatPreviewState();
}

class ChatPreviewState extends State<ChatPreview>
    with TickerProviderStateMixin {
  int? playingMessageId = 0;
  // 显示音频播放器的状态
  bool showAudioPlayer = false;
  // 是否显示音频播放器加载中
  bool audioLoadding = false;

  String text = '';
  // String showText = '';
  late AnimationController animationController;
  final Duration animationDuration = const Duration(milliseconds: 40);
  int currentTextIndex = 0;
  // bool isReady = false;
  // bool isReadyRecord = false;
  Message? recordMessage;

  @override
  void initState() {
    widget.controller.addListener(() {
      setState(() {});
    });
    if (widget.audioPlayerController != null) {
      widget.audioPlayerController!.onPlayStopped = () {
        showAudioPlayer = false;
        audioLoadding = false;
        setState(() {});
      };
      widget.audioPlayerController!.onPlayAudioStarted = () {
        setState(() {
          showAudioPlayer = true;
        });
      };
      widget.audioPlayerController!.onPlayCompletion = () {
        playingMessageId = 0;
        showAudioPlayer = false;
        setState(() {});
      };

      widget.audioPlayerController!.onPlayAudioLoading = (loading) {
        setState(() {
          audioLoadding = loading;
        });
      };
    }

    animationController = AnimationController(
      duration: animationDuration,
      vsync: this,
    )..addListener(() {
        if (currentTextIndex < text.length) {
          setState(() {
            currentTextIndex++;
          });
        } else if (currentTextIndex >= text.length) {
          animationController.stop();
          text = '';
          // currentTextIndex = 0;
          recordMessage?.isReady = true;
          setState(() {});
          recordMessage = null;

          if (widget.onReadyAnimedEvent != null) {
            widget.onReadyAnimedEvent!();
          }
        }
      });

    super.initState();
  }

  void refreshState() {
    setState(() {});
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final customColors = Theme.of(context).extension<CustomColors>()!;

    var messages = widget.messages.reversed.toList();

    return Column(
      children: [
        Flexible(
          child: CustomScrollView(
            reverse: true,
            shrinkWrap: true,
            controller: widget.scrollController,
            slivers: [
              SliverToBoxAdapter(
                child: ListView.builder(
                  itemCount: messages.length,
                  shrinkWrap: true,
                  reverse: true,
                  physics: const BouncingScrollPhysics(),
                  padding: widget.padding,
                  cacheExtent: MediaQuery.of(context).size.height * 12,
                  itemBuilder: (context, index) {
                    final message = messages[index];

                    return Column(
                      children: [
                        // 问题不为空
                        // if (widget.questionWidget != null)
                        //   widget.questionWidget!,

                        // 消息类型为 hide，不展示
                        if (message.message.type == MessageType.hide)
                          Container(),

                        if (message.message.type != MessageType.hide)
                          Row(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: [
                              // 消息选择模式，显示选择框
                              if (widget.controller.selectMode &&
                                  !message.message.isSystem())
                                Checkbox(
                                  value: widget.controller
                                      .isMessageSelected(message.message.id!),
                                  activeColor: customColors.linkColor,
                                  onChanged: (value) {
                                    if (value != null && value) {
                                      widget.controller
                                          .selectMessage(message.message.id!);
                                    } else {
                                      widget.controller
                                          .unSelectMessage(message.message.id!);
                                    }
                                  },
                                ),

                              // 消息主体部分
                              Expanded(
                                child: widget.supportBloc
                                    ? BlocBuilder<ChatMessageBloc,
                                        ChatMessageState>(
                                        buildWhen: (previous, current) =>
                                            (current is ChatMessageUpdated &&
                                                current.message.id ==
                                                    message.message.id),
                                        builder: (context, state) {
                                          return Container(
                                            padding: const EdgeInsets.symmetric(
                                              horizontal: 4,
                                              vertical: 7,
                                            ),
                                            child: _buildMessageBox(
                                              context,
                                              customColors,
                                              _resolveMessage(state, message),
                                              message.state,
                                              state,
                                              index,
                                            ),
                                          );
                                        },
                                      )
                                    : Container(
                                        padding: const EdgeInsets.symmetric(
                                          horizontal: 4,
                                          vertical: 7,
                                        ),
                                        child: _buildMessageBox(
                                          context,
                                          customColors,
                                          message.message,
                                          message.state,
                                          null,
                                          index,
                                        ),
                                      ),
                              ),
                            ],
                          ),
                      ],
                    );
                  },
                ),
              ),

              //问题不为空
              if (widget.questionWidget != null)
                SliverToBoxAdapter(
                  child: widget.questionWidget!,
                ),
            ],
          ),
        ),
      ],
    );
  }

  Message _resolveMessage(ChatMessageState state, MessageWithState message) {
    if (state is ChatMessageUpdated && state.message.id == message.message.id) {
      return state.message;
    }

    return message.message;
  }

  /// 构建消息框
  Widget _buildMessageBox(
    BuildContext context,
    CustomColors customColors,
    Message message,
    MessageState state,
    ChatMessageState? current,
    int index,
  ) {
    // 系统消息
    if (message.isSystem()) {
      return Align(
        alignment: Alignment.center,
        child: Container(
          padding: const EdgeInsets.symmetric(
            horizontal: 16,
            vertical: 5,
          ),
          child: Text(
            message.isTimeline()
                ? message.friendlyTime()
                : message.text.getString(context),
            style: Theme.of(context).textTheme.bodySmall,
          ),
        ),
      );
    }

    final showTranslate = state.showTranslate &&
        state.translateText != null &&
        state.translateText != '';

    final extra = index == 0 ? message.decodeExtra() : null;
    final extraInfo = extra != null ? extra['info'] ?? '' : '';

    if (message.role == Role.receiver && message.id == recordMessage?.id) {
      // if (!message.isReady && message.status == 1) {
      //   recordMessage = message;
      // }
      if (message.isReady && currentTextIndex < text.length && animationController.isAnimating) {
        message.isReady = false;
        recordMessage = message;
      } else if (message.isReady && currentTextIndex == 0) {
        message.isReady = false;
        recordMessage = message;
      }
    }

    // 普通消息
    return Align(
      alignment:
          message.role == Role.sender ? Alignment.topRight : Alignment.topLeft,
      child: ConstrainedBox(
        constraints: BoxConstraints(maxWidth: _chatBoxMaxWidth(context)),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            if (message.images != null && message.images!.isNotEmpty)
              Container(
                margin: message.role == Role.sender
                    ? const EdgeInsets.fromLTRB(0, 0, 10, 7)
                    : const EdgeInsets.fromLTRB(10, 0, 0, 7),
                child: ConstrainedBox(
                  constraints: BoxConstraints(
                    maxWidth: _chatBoxImagePreviewWidth(
                      context,
                      (message.images ?? []).length,
                    ),
                  ),
                  child: FileUploadPreview(images: message.images ?? []),
                ),
              ),
            Row(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                // 消息头像
                // buildAvatar(message),
                // 消息内容部分
                ConstrainedBox(
                  constraints: BoxConstraints(
                    maxWidth: _chatBoxMaxWidth(context) - 20,
                  ),
                  child: ClipRRect(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        // 发送人名称
                        if (message.role == Role.receiver &&
                            widget.senderNameBuilder != null)
                          widget.senderNameBuilder!(message) ??
                              const SizedBox(),
                        Wrap(
                          crossAxisAlignment: WrapCrossAlignment.end,
                          children: [
                            // 错误指示
                            if (message.role == Role.sender &&
                                message.statusIsFailed())
                              buildErrorIndicator(
                                  message, state, context, index),
                            // 消息主体
                            GestureDetector(
                              // 选择模式下，单击切换选择与否
                              // 非选择模式下，单击隐藏键盘
                              onTap: () {
                                if (widget.controller.selectMode) {
                                  widget.controller
                                      .toggleMessageSelected(message.id!);
                                }
                                FocusScope.of(context)
                                    .requestFocus(FocusNode());
                              },

                              child: Stack(
                                children: [
                                  Container(
                                    margin: message.role == Role.sender
                                        ? const EdgeInsets.fromLTRB(
                                            0, 0, 10, 40)
                                        : ((message.statusPending() ||
                                                !message.isReady))
                                            ? const EdgeInsets.fromLTRB(
                                                10, 0, 0, 7)
                                            : const EdgeInsets.fromLTRB(
                                                10, 0, 0, 40),
                                    decoration: BoxDecoration(
                                        borderRadius: message.role ==
                                                Role.sender
                                            ? const BorderRadius.only(
                                                topLeft: Radius.circular(15),
                                                topRight: Radius.circular(15),
                                                bottomLeft: Radius.circular(15))
                                            : const BorderRadius.only(
                                                topLeft: Radius.circular(15),
                                                topRight: Radius.circular(15),
                                                bottomRight:
                                                    Radius.circular(15)),
                                        color: message.role == Role.receiver
                                            ? customColors
                                                .chatRoomReplyBackground
                                            : null,
                                        gradient: message.role == Role.sender
                                            ? const LinearGradient(
                                                colors: [
                                                  Color(0xFF16DFEB),
                                                  Color(0xFF578AFC),
                                                ],
                                                begin: Alignment.centerLeft,
                                                end: Alignment.centerRight,
                                              )
                                            : null),
                                    padding: const EdgeInsets.symmetric(
                                      horizontal: 10,
                                      vertical: 6,
                                    ),
                                    child: Builder(
                                      builder: (context) {
                                        if ((message.statusPending() ||
                                                !message.isReady) &&
                                            message.text.isEmpty) {
                                          return LoadingAnimationWidget
                                              .waveDots(
                                            color: customColors.weakLinkColor!,
                                            size: 25,
                                          );
                                        }

                                        var text = message.text
                                            .replaceAll('\\n', '\n');
                                        if (message.role == Role.receiver && !message.isReady) {
                                          this.text = text;
                                        }

                                        return Column(
                                          mainAxisSize: MainAxisSize.min,
                                          crossAxisAlignment:
                                              CrossAxisAlignment.start,
                                          children: [
                                            if (message.isReady || current is ChatMessagesLoaded || message.role == Role.sender)
                                              Markdown(
                                                textStyle: const TextStyle(
                                                    fontSize: 15,
                                                    color: Colors.white),
                                                data: text.trim(),
                                                onUrlTap: (value) =>
                                                    onMarkdownUrlTap(value),
                                              )
                                            else
                                              AnimatedBuilder(
                                                  animation: animationController,
                                                  builder: (context, animateState) {
                                                    var showText = text.substring(0, currentTextIndex);
                                                    if (!message.isReady) {
                                                      showText += ' ▌';
                                                    }
                                                    return Markdown(
                                                      textStyle:
                                                          const TextStyle(
                                                              fontSize: 15,
                                                              color:
                                                                  Colors.white),
                                                      data: showText.trim(),
                                                      onUrlTap: (value) =>
                                                          onMarkdownUrlTap(
                                                              value),
                                                    );
                                                  }),
                                            // state.showMarkdown
                                            // Markdown(
                                            //   textStyle: const TextStyle(
                                            //       fontSize: 15,
                                            //       color: Colors.white),
                                            //   data: text.trim(),
                                            //   onUrlTap: (value) =>
                                            //       onMarkdownUrlTap(value),
                                            // )
                                            // : SelectableText(
                                            //     text,
                                            //     style: TextStyle(
                                            //       color: customColors
                                            //           .chatRoomSenderText,
                                            //     ),
                                            //   ),
                                          ],
                                        );
                                      },
                                    ),
                                  ),

                                  Visibility(
                                    visible: message.role == Role.sender,
                                    child: Positioned(
                                      bottom: 0,
                                      right: 10,
                                      width: 32,
                                      height: 32,
                                      child: GestureDetector(
                                        onTap: () {
                                          var text = message.text
                                              .replaceAll('\\n', '\\\n');
                                          var editText = text.trim();
                                          NotificationCenter().notify(
                                              widget.keyIndex == 1 ? HOME_EDIT_INPUT_TEXT_ONE_NOTIF : HOME_EDIT_INPUT_TEXT_TWO_NOTIF,
                                              data: editText);
                                        },
                                        child: Container(
                                          decoration: BoxDecoration(
                                            borderRadius:
                                                BorderRadius.circular(8),
                                            color:
                                                Colors.white.withOpacity(0.12),
                                          ),
                                          padding: const EdgeInsets.only(
                                              left: 9,
                                              right: 9,
                                              top: 7,
                                              bottom: 7),
                                          child: imgWidget(15.5, 17, 'edit'),
                                        ),
                                      ),
                                    ),
                                  ),
                                  Visibility(
                                    visible: message.role == Role.receiver &&
                                        !(message.statusPending() ||
                                            !message.isReady),
                                    child: Positioned(
                                      bottom: 0,
                                      right: 0,
                                      left: 10,
                                      height: 32,
                                      // width: _chatBoxMaxWidth(context) - 20,
                                      child: Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.spaceBetween,
                                        children: [
                                          //播放
                                          GestureDetector(
                                            onTap: () {
                                              if (audioLoadding) {
                                                return;
                                              }
                                              if (showAudioPlayer) {
                                                if (widget
                                                        .audioPlayerController !=
                                                    null) {
                                                  playingMessageId = 0;
                                                  widget.audioPlayerController!
                                                      .stop();
                                                }
                                              } else {
                                                playingMessageId =
                                                    message.serverId;
                                                widget.onSpeakEvent!(message);
                                              }
                                            },
                                            child: Row(
                                              children: [
                                                Container(
                                                  // width: 65,
                                                  height: 32,
                                                  decoration: BoxDecoration(
                                                    borderRadius:
                                                        BorderRadius.circular(
                                                            8),
                                                    color: Colors.white
                                                        .withOpacity(0.12),
                                                  ),
                                                  padding:
                                                      const EdgeInsets.only(
                                                          left: 9,
                                                          right: 9,
                                                          top: 7,
                                                          bottom: 7),
                                                  child: Row(
                                                    children: [
                                                      imgWidget(
                                                          17,
                                                          17,
                                                          (showAudioPlayer &&
                                                                  message.serverId ==
                                                                      playingMessageId)
                                                              ? 'play'
                                                              : 'stop'),
                                                      const SizedBox(
                                                        width: 5,
                                                      ),
                                                      // gif
                                                      if (widget.audioPlayerController !=
                                                              null &&
                                                          showAudioPlayer &&
                                                          message.serverId ==
                                                              playingMessageId)
                                                        EnhancedAudioPlayer(
                                                          controller: widget
                                                              .audioPlayerController!,
                                                          loading:
                                                              audioLoadding,
                                                          showAudioPlayer:
                                                              showAudioPlayer,
                                                        ),
                                                    ],
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                          //更多
                                          Container(
                                            height: 32,
                                            decoration: BoxDecoration(
                                              borderRadius:
                                                  BorderRadius.circular(8),
                                              color: Colors.white
                                                  .withOpacity(0.12),
                                            ),
                                            child: Row(
                                              children: [
                                                GestureDetector(
                                                  onTap: () {
                                                    var replacedString =
                                                        message.text.replaceAll(
                                                            '\\n', '\\\n');
                                                    replacedString =
                                                        replacedString
                                                            .replaceAll(
                                                                '\\', '');

                                                    FlutterClipboard.copy(
                                                            replacedString)
                                                        .then((value) {
                                                      showSuccessMessage(
                                                          '已复制到剪贴板');
                                                    });
                                                  },
                                                  child: Container(
                                                      padding:
                                                          const EdgeInsets.only(
                                                              right: 2),
                                                      width: 45,
                                                      height: 30,
                                                      child: Center(
                                                        child: imgWidget(
                                                            17, 17, 'copy'),
                                                      )),
                                                ),
                                                Container(
                                                  margin: const EdgeInsets.only(
                                                      top: 6.5, bottom: 6.5),
                                                  color:
                                                      const Color(0xFF4B4A4D),
                                                  width: 1,
                                                ),
                                                GestureDetector(
                                                  onTap: () {
                                                    EasyLoading.show(
                                                        status: '请稍等...');
                                                    APIServer()
                                                        .clickLike(
                                                            message.serverId ??
                                                                0,
                                                            message.like == 0
                                                                ? 1
                                                                : 0)
                                                        .then((value) {
                                                      EasyLoading.dismiss();

                                                      message.like =
                                                          message.like == 0
                                                              ? 1
                                                              : 0;
                                                      if (widget.onLikeEvent !=
                                                          null) {
                                                        widget.onLikeEvent!(
                                                            message, index);
                                                      }

                                                      setState(() {});
                                                      context
                                                          .read<RoomBloc>()
                                                          .add(RoomLoadEvent(
                                                              message.roomId!,
                                                              cascading:
                                                                  false));
                                                    }).onError((error,
                                                            stackTrace) {
                                                      EasyLoading.dismiss();
                                                      showErrorMessage(
                                                          resolveError(
                                                              context, error!));
                                                    });
                                                  },
                                                  child: SizedBox(
                                                      width: 40,
                                                      height: 30,
                                                      child: Center(
                                                          child: imgWidget(
                                                              17,
                                                              17,
                                                              message.like == 0
                                                                  ? 'zan'
                                                                  : 'yizan'))),
                                                ),
                                                Container(
                                                  margin: const EdgeInsets.only(
                                                      top: 6.5, bottom: 6.5),
                                                  color:
                                                      const Color(0xFF4B4A4D),
                                                  width: 1,
                                                ),
                                                GestureDetector(
                                                  onTap: () {
                                                    EasyLoading.show(
                                                        status: '请稍等...');
                                                    APIServer()
                                                        .clickCollect(
                                                            message.serverId ??
                                                                0,
                                                            message.collection ==
                                                                    0
                                                                ? 1
                                                                : 0)
                                                        .then((value) {
                                                      EasyLoading.dismiss();

                                                      message.collection =
                                                          message.collection ==
                                                                  0
                                                              ? 1
                                                              : 0;
                                                      if (widget
                                                              .onCollectionEvent !=
                                                          null) {
                                                        widget.onCollectionEvent!(
                                                            message, index);
                                                      }

                                                      setState(() {});
                                                      context
                                                          .read<RoomBloc>()
                                                          .add(RoomLoadEvent(
                                                              message.roomId!,
                                                              cascading:
                                                                  false));
                                                    }).onError((error,
                                                            stackTrace) {
                                                      EasyLoading.dismiss();
                                                      showErrorMessage(
                                                          resolveError(
                                                              context, error!));
                                                    });
                                                  },
                                                  child: Container(
                                                      padding:
                                                          const EdgeInsets.only(
                                                              left: 2),
                                                      width: 45,
                                                      height: 30,
                                                      child: Center(
                                                        child: imgWidget(
                                                            17,
                                                            17,
                                                            message.collection ==
                                                                    0
                                                                ? 'collection0'
                                                                : 'collection1'),
                                                      )),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                  ),
                                  // if (extraInfo.isNotEmpty)
                                  //   Positioned(
                                  //     top: 5,
                                  //     right: 5,
                                  //     child: InkWell(
                                  //       onTap: () {
                                  //         showCustomBeautyDialog(
                                  //           context,
                                  //           type: QuickAlertType.warning,
                                  //           confirmBtnText: AppLocale.gotIt
                                  //               .getString(context),
                                  //           showCancelBtn: false,
                                  //           title: '温馨提示',
                                  //           child: Markdown(
                                  //             data: extraInfo,
                                  //             onUrlTap: (value) {
                                  //               onMarkdownUrlTap(value);
                                  //               context.pop();
                                  //             },
                                  //             textStyle: TextStyle(
                                  //               fontSize: 14,
                                  //               color: customColors
                                  //                   .dialogDefaultTextColor,
                                  //             ),
                                  //           ),
                                  //         );
                                  //       },
                                  //       child: Icon(
                                  //         Icons.info_outline,
                                  //         size: 16,
                                  //         color: customColors.weakLinkColor
                                  //             ?.withAlpha(50),
                                  //       ),
                                  //     ),
                                  //   ),
                                ],
                              ),
                            ),
                          ],
                        ),
                        if (showTranslate)
                          Container(
                            margin: message.role == Role.sender
                                ? const EdgeInsets.fromLTRB(7, 10, 14, 7)
                                : const EdgeInsets.fromLTRB(10, 10, 0, 7),
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(10),
                              color: message.role == Role.receiver
                                  ? customColors
                                      .chatRoomReplyBackgroundSecondary
                                  : customColors
                                      .chatRoomSenderBackgroundSecondary,
                            ),
                            padding: const EdgeInsets.symmetric(
                                horizontal: 10, vertical: 5),
                            child: Builder(
                              builder: (context) {
                                return Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    state.showMarkdown
                                        ? Markdown(data: state.translateText!)
                                        : SelectableText(
                                            state.translateText!,
                                            style: TextStyle(
                                              color: customColors
                                                  .chatRoomSenderText,
                                            ),
                                          ),
                                    const Row(
                                      mainAxisSize: MainAxisSize.min,
                                      children: [
                                        Icon(
                                          Icons.check_circle,
                                          size: 12,
                                          color: Colors.green,
                                        ),
                                        SizedBox(width: 5),
                                        Text(
                                          '翻译完成',
                                          style: TextStyle(
                                            fontSize: 12,
                                            color: Color.fromARGB(
                                                255, 145, 145, 145),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                );
                              },
                            ),
                          ),
                        if (widget.messageFooterBuilder != null)
                          widget.messageFooterBuilder!(message),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget buildErrorIndicator(
    Message message,
    MessageState state,
    BuildContext context,
    int index,
  ) {
    return Container(
      margin: const EdgeInsets.only(right: 5, bottom: 10),
      child: GestureDetector(
        onTapUp: (details) {
          if (widget.controller.selectMode || message.isSystem()) {
            return;
          }

          HapticFeedbackHelper.mediumImpact();

          var confirmMessage = '';
          if (message.extra != null && message.extra!.isNotEmpty) {
            try {
              final extra = jsonDecode(message.extra!);
              if (extra['error'] != null && extra['error'] != '') {
                var e1 = extra['error'];
                try {
                  e1 = (e1 as String).getString(context);
                  // ignore: empty_catches
                } catch (ignored) {}
                confirmMessage = e1;
              }
              // ignore: empty_catches
            } catch (ignored) {}
          }

          openConfirmDialog(
            context,
            // confirmMessage,
            '',
            () {
              widget.onResentEvent!(message, index);
            },
            title: Text(AppLocale.robotHasSomeError.getString(context)),
            confirmText: '重新发送',
          );
        },
        child: const Icon(Icons.error, color: Colors.red, size: 20),
      ),
    );
  }

  void onMarkdownUrlTap(value) {
    if (value.startsWith("great-app://")) {
      var route = value.substring('great-app://'.length);
      context.push(route);
    } else if (value.startsWith("great-command://")) {
      var command = value.substring('great-command://'.length);
      switch (command) {
        case "reset-context":
          if (widget.onResetContext != null) {
            widget.onResetContext!();
          }
          break;
      }
    } else {
      launchUrlString(value);
    }
  }

  Widget buildAvatar(Message message) {
    if (widget.avatarBuilder != null) {
      final avatar = widget.avatarBuilder!(message);
      if (avatar != null) {
        return avatar;
      }
    }

    if (widget.robotAvatar != null) {
      if (message.role == Role.receiver && message.avatarUrl != null) {
        return RemoteAvatar(
          avatarUrl: message.avatarUrl!,
          size: 30,
        );
      }

      if (message.role == Role.receiver) {
        return widget.robotAvatar!;
      }
    }

    return const SizedBox();
  }

  /// 点击消息后控制操作弹窗菜单
  void _handleMessageTapControl(
    BuildContext context,
    Offset? offset,
    Message message,
    MessageState state,
    int index,
  ) {
    if (widget.controller.selectMode || message.isSystem()) {
      return;
    }

    HapticFeedbackHelper.mediumImpact();

    final showTranslate = state.showTranslate &&
        state.translateText != null &&
        state.translateText != '';

    BotToast.showAttachedWidget(
      target: offset,
      duration: const Duration(seconds: 8),
      animationDuration: const Duration(milliseconds: 200),
      animationReverseDuration: const Duration(milliseconds: 200),
      preferDirection: PreferDirection.topCenter,
      ignoreContentClick: false,
      onlyOne: true,
      allowClick: true,
      enableSafeArea: true,
      attachedBuilder: (cancel) => AttachedButtonPanel(
        buttons: [
          TextButton.icon(
            onPressed: () {
              openFullscreenDialog(
                context,
                child: Container(
                  margin: const EdgeInsets.only(top: 15, bottom: 30),
                  child: EnhancedSelectableText(
                    text: message.text,
                  ),
                ),
                title: '选择文本',
              );

              cancel();
            },
            label: const Text(''),
            icon: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Icon(
                  state.showMarkdown ? Icons.text_format : Icons.preview,
                  color: const Color.fromARGB(255, 255, 255, 255),
                  size: 14,
                ),
                const Text(
                  "文本",
                  style: TextStyle(fontSize: 12, color: Colors.white),
                ),
              ],
            ),
          ),
          TextButton.icon(
            onPressed: () {
              FlutterClipboard.copy(message.text).then((value) {
                showSuccessMessage('已复制到剪贴板');
              });
              cancel();
            },
            label: const Text(''),
            icon: const Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Icon(
                  Icons.copy,
                  color: Color.fromARGB(255, 255, 255, 255),
                  size: 14,
                ),
                Text(
                  "复制",
                  style: TextStyle(fontSize: 12, color: Colors.white),
                ),
              ],
            ),
          ),
          if (Ability().supportTranslate && widget.stateManager != null)
            TextButton.icon(
                onPressed: () {
                  cancel();

                  if (showTranslate) {
                    widget.stateManager!
                        .setState(message.roomId!, message.id!,
                            state..showTranslate = false)
                        .then((value) {
                      setState(() {});
                      context.read<RoomBloc>().add(
                          RoomLoadEvent(message.roomId!, cascading: false));
                    });
                  } else {
                    if (state.translateText != null &&
                        state.translateText != '') {
                      widget.stateManager!
                          .setState(message.roomId!, message.id!,
                              state..showTranslate = true)
                          .then((value) {
                        setState(() {});
                        context.read<RoomBloc>().add(
                            RoomLoadEvent(message.roomId!, cascading: false));
                      });
                      return;
                    }

                    APIServer().translate(message.text).then((value) {
                      widget.stateManager!
                          .setState(
                        message.roomId!,
                        message.id!,
                        state
                          ..translateText = value.result!
                          ..showTranslate = true,
                      )
                          .then((value) {
                        setState(() {});
                        context.read<RoomBloc>().add(
                            RoomLoadEvent(message.roomId!, cascading: false));
                      });
                    }).onError((error, stackTrace) {
                      showErrorMessage(resolveError(context, error!));
                    });
                  }
                },
                label: const Text(''),
                icon: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    const Icon(
                      Icons.translate,
                      color: Color.fromARGB(255, 255, 255, 255),
                      size: 14,
                    ),
                    Text(
                      showTranslate ? '隐藏' : '翻译',
                      style: const TextStyle(fontSize: 12, color: Colors.white),
                    )
                  ],
                )),
          TextButton.icon(
              onPressed: () {
                widget.controller.enterSelectMode();
                cancel();
              },
              label: const Text(''),
              icon: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  const Icon(
                    Icons.select_all,
                    color: Color.fromARGB(255, 255, 255, 255),
                    size: 14,
                  ),
                  Text(
                    AppLocale.select.getString(context),
                    style: const TextStyle(fontSize: 12, color: Colors.white),
                  )
                ],
              )),
          if (widget.onDeleteMessage != null)
            TextButton.icon(
              onPressed: () {
                widget.onDeleteMessage!(message.id!);
                cancel();
              },
              label: const Text(''),
              icon: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  const Icon(
                    Icons.delete,
                    color: Color.fromARGB(255, 255, 255, 255),
                    size: 14,
                  ),
                  Text(
                    AppLocale.delete.getString(context),
                    style: const TextStyle(fontSize: 12, color: Colors.white),
                  )
                ],
              ),
            ),
          if (Ability().supportSpeak && widget.onSpeakEvent != null)
            TextButton.icon(
              onPressed: () {
                cancel();
                widget.onSpeakEvent!(message);
              },
              label: const Text(''),
              icon: const Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(
                    Icons.record_voice_over,
                    color: Color.fromARGB(255, 255, 255, 255),
                    size: 14,
                  ),
                  Text(
                    '朗读',
                    style: TextStyle(fontSize: 12, color: Colors.white),
                  )
                ],
              ),
            ),
          if (message.role == Role.sender && widget.onResentEvent != null)
            TextButton.icon(
              onPressed: () {
                widget.onResentEvent!(message, index);
                cancel();
              },
              label: const Text(''),
              icon: const Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(
                    Icons.restore,
                    color: Color.fromARGB(255, 255, 255, 255),
                    size: 14,
                  ),
                  Text(
                    '重发',
                    style: TextStyle(fontSize: 12, color: Colors.white),
                  ),
                ],
              ),
            ),
        ],
      ),
    );
  }

  /// 获取聊天框的最大宽度
  double _chatBoxMaxWidth(BuildContext context) {
    var screenWidth = ScreenUtil().screenWidth;
    if (screenWidth >= CustomSize.maxWindowSize) {
      return CustomSize.maxWindowSize;
    }
    return screenWidth;
  }

  /// 获取图片预览的最大宽度
  double _chatBoxImagePreviewWidth(BuildContext context, int imageCount) {
    final expect = _chatBoxMaxWidth(context) / 1.3;
    final max = imageCount > 1 ? 600.0 : 400.0;
    return expect > max ? max : expect;
  }

  void inAppReviewEvent() async {
    var value = await AppUtil().isAppReview();
    if (!value) {
      final InAppReview inAppReview = InAppReview.instance;

      if (await inAppReview.isAvailable()) {
        inAppReview.requestReview().then((value) {
          print('-------------->requestReview ');
        });
      }
    }
  }
}

/// ChatPreview 控制器
class ChatPreviewController extends ChangeNotifier {
  /// 是否处于多选模式
  bool _selectMode = false;

  /// 选中的消息ID
  final _selectedMessageIds = <int>{};

  /// 所有消息
  List<MessageWithState>? _allMessages;

  bool get selectMode => _selectMode;
  Set<int> get selectedMessageIds => _selectedMessageIds;

  /// 获取选中的消息
  List<MessageWithState> selectedMessages() {
    if (_allMessages == null || _allMessages!.isEmpty) {
      return [];
    }

    return _allMessages!
        .where((element) => _selectedMessageIds.contains(element.message.id))
        .toList();
  }

  /// 设置所有消息
  void setAllMessageIds(List<MessageWithState> messages) {
    _allMessages = messages.where((e) => !e.message.isSystem()).toList();
  }

  void toggleSelectMode() {
    _selectMode = !_selectMode;
    notifyListeners();
  }

  void exitSelectMode() {
    _selectMode = false;
    _selectedMessageIds.clear();
    notifyListeners();
  }

  void enterSelectMode() {
    _selectMode = true;
    _selectedMessageIds.clear();
    notifyListeners();
  }

  void toggleMessageSelected(int messageId) {
    if (_selectedMessageIds.contains(messageId)) {
      _selectedMessageIds.remove(messageId);
    } else {
      _selectedMessageIds.add(messageId);
    }
    notifyListeners();
  }

  void selectAllMessage() {
    if (_allMessages == null || _allMessages!.isEmpty) {
      return;
    }

    if (_selectedMessageIds.length == _allMessages!.length) {
      _selectedMessageIds.clear();
      notifyListeners();
      return;
    }

    _selectedMessageIds.clear();
    for (var msg in _allMessages!) {
      _selectedMessageIds.add(msg.message.id!);
    }

    notifyListeners();
  }

  void selectMessage(int id) {
    _selectedMessageIds.add(id);
    notifyListeners();
  }

  void unSelectMessage(int id) {
    _selectedMessageIds.remove(id);
    notifyListeners();
  }

  bool isMessageSelected(int id) {
    return _selectedMessageIds.contains(id);
  }
}
